//:C04:Showerr.cpp {RunByHand}
// Un-comment error generators.
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include "../require.h"
using namespace std;

const string USAGE = 
  "usage: showerr filename chapnum\n"
  "where filename is a C++ source file\n"
  "and chapnum is the chapter name it's in.\n"
  "Finds lines commented with //! and removes\n"
  "the comment, appending //(#) where # is unique\n"
  "across all files. so you can determine\n"
  "if your compiler finds the error.\n"
  "showerr /r\n"
  "resets the unique counter.";

class Showerr {
  const int CHAP;
  const string MARKER, FNAME;
  // File containing error number counter:
  const string ERRNUM;
  // File containing error lines:
  const string ERRFILE;
  stringstream edited;  // Edited file
  int counter;
  public:
    Showerr(const string& f, const string& en,
      const string& ef, int c) 
    : CHAP(c),MARKER("//!"), FNAME(f), ERRNUM(en),
      ERRFILE(ef), counter(0) {} 
    void replaceErrors() {
      ifstream infile(FNAME.c_str());
      assure(infile,FNAME.c_str());
      ifstream count(ERRNUM.c_str());
      if(count) {
        count >> counter;
      }
      int linecount = 1;
      string buf;
      ofstream errlines(ERRFILE.c_str(), ios::app);
      assure(errlines, ERRFILE.c_str());
      while(getline(infile, buf)) {
        // Find marker at start of line:
        size_t pos = buf.find(MARKER);
        if(pos != string::npos) {
          // Erase marker:  
          buf.erase(pos, MARKER.size() + 1);
          // Append counter & error info:
          ostringstream out;  
          out << buf << " // (" << ++counter << ") "
              << "Chapter " << CHAP
              << " File: " << FNAME
              << " Line " << linecount << endl;
              edited << out.str();
              errlines << out.str();    // Append error file
        }
        else {
          edited << buf << "\n";   // Just copy  
        }
        ++linecount;
      }
    }  

    void saveFile() {
      ofstream outfile(FNAME.c_str()); // Overwrites
      assure(outfile, FNAME.c_str());
      outfile << edited.rdbuf();
      ofstream count(ERRNUM.c_str());    // Overwrites
      assure(count, ERRNUM.c_str());
      count << counter;    // Save new counter
    }
};  

int main(int argc, char* argv[]) {
  const string ERRCOUNT("../errnum.txt"),
    ERRFILE("../errlines.txt");
  requireMinArgs(argc, 1,USAGE.c_str());    
  if(argv[1][0] == '/' || argv[1][0] == '-') {
    // Allow for other switches:
    switch(argv[1][1]) {
      case 'r': 
      case 'R':
        cout << "reset counter" << endl;
      default:
        cerr << USAGE << endl;
        return EXIT_FAILURE;
    }
  }
  if(argc == 3) {
    Showerr s(argv[1], ERRCOUNT, ERRFILE, atoi(argv[2]));
    s.replaceErrors();
    s.saveFile();
  }
}

